{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Fabric SDK Python\n",
    "\n",
    "Before getting started, make sure the Python SDK is installed properly and the network is up and running.\n",
    "For more information regarding installation process and how to set up the network please refer to [this](https://github.com/hyperledger/fabric-sdk-py/blob/main/docs/source/tutorial.md)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prepare a Testing Environment\n",
    "\n",
    "### Install Fabric SDK\n",
    "\n",
    "```bash\n",
    "$ git clone https://github.com/hyperledger/fabric-sdk-py.git\n",
    "$ cd fabric-sdk-py\n",
    "$ make install\n",
    "```\n",
    "\n",
    "### Setup a Fabric Network\n",
    "\n",
    "If you already have a running fabric network, ignore this.\n",
    "\n",
    "To start an example fabric network you can simply run the following command:\n",
    "\n",
    "```bash\n",
    "$ HLF_VERSION=1.4.6\n",
    "$ docker pull hyperledger/fabric-peer:${HLF_VERSION}\n",
    "$ docker pull hyperledger/fabric-orderer:${HLF_VERSION}\n",
    "$ docker pull hyperledger/fabric-ca:${HLF_VERSION}\n",
    "$ docker pull hyperledger/fabric-ccenv:${HLF_VERSION}\n",
    "$ docker-compose -f test/fixtures/docker-compose-2orgs-4peers-tls.yaml up\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the bellow code block to import an instance of a client from the network profile already provided"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Init client with profile=test/fixtures/network.json\n",
      "create org with name=orderer.example.com\n",
      "create org with name=org1.example.com\n",
      "create org with name=org2.example.com\n",
      "create ca with name=ca-org1\n",
      "create ca with name=ca-org2\n",
      "Import orderers = dict_keys(['orderer.example.com'])\n",
      "Import peers = dict_keys(['peer0.org1.example.com', 'peer1.org1.example.com', 'peer0.org2.example.com', 'peer1.org2.example.com'])\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'orderer.example.com': <hfc.fabric.organization.Organization object at 0x7fbb95a5ef60>, 'org1.example.com': <hfc.fabric.organization.Organization object at 0x7fbb977e90f0>, 'org2.example.com': <hfc.fabric.organization.Organization object at 0x7fbb95938588>}\n",
      "{'peer0.org1.example.com': <hfc.fabric.peer.Peer object at 0x7fbb959386a0>, 'peer1.org1.example.com': <hfc.fabric.peer.Peer object at 0x7fbb95938dd8>, 'peer0.org2.example.com': <hfc.fabric.peer.Peer object at 0x7fbb95938a90>, 'peer1.org2.example.com': <hfc.fabric.peer.Peer object at 0x7fbb95938860>}\n",
      "{'orderer.example.com': <hfc.fabric.orderer.Orderer object at 0x7fbb95938978>}\n",
      "{'ca-org1': <hfc.fabric.certificateAuthority.certificateAuthority object at 0x7fbb95938828>, 'ca-org2': <hfc.fabric.certificateAuthority.certificateAuthority object at 0x7fbb959389b0>}\n"
     ]
    }
   ],
   "source": [
    "from hfc.fabric import Client\n",
    "\n",
    "cli = Client(net_profile=\"test/fixtures/network.json\")\n",
    "\n",
    "print(cli.organizations)  # orgs in the network\n",
    "print(cli.peers)  # peers in the network\n",
    "print(cli.orderers)  # orderers in the network\n",
    "print(cli.CAs)  # ca nodes in the network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "org1_admin = cli.get_user(org_name='org1.example.com', name='Admin') # User instance with the Org1 admin's certs\n",
    "org2_admin = cli.get_user(org_name='org2.example.com', name='Admin') # User instance with the Org2 admin's certs\n",
    "orderer_admin = cli.get_user(org_name='orderer.example.com', name='Admin') # User instance with the orderer's certs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the bellow code snippet to create a channel with the name 'business' channel.\n",
    "This command will return True if the channel was created successfully."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "FABRIC_CFG_PATH set to /home/rohan/Documents/fabric-sdk-py/test/fixtures/e2e_cli/\n",
      "Configtx file successfully created in current             directory\n",
      "{'tx_id': '3595d96aa2fda8c12e225fbd4689bf8e511cda14c742a27887fa94321aee9686', 'nonce': b'\\x94\\x13\\xc3\\xd9\\xb3\\xba\\xe7V\\xb8Z\\xd3\\xad\\x9b\\xb9<\\xbe\\xd1\\xc8Y\\xd9{\\xe1d\\xd5', 'signatures': [b\"\\n\\xd3\\x06\\n\\xb6\\x06\\n\\x07Org1MSP\\x12\\xaa\\x06-----BEGIN CERTIFICATE-----\\nMIICKjCCAdCgAwIBAgIQEn3uLYlL4sXXQBS1/k8u7zAKBggqhkjOPQQDAjBzMQsw\\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\\nb3JnMS5leGFtcGxlLmNvbTAeFw0xODEwMTkwMzQ4MDBaFw0yODEwMTYwMzQ4MDBa\\nMGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\\nYW4gRnJhbmNpc2NvMQ8wDQYDVQQLEwZjbGllbnQxHzAdBgNVBAMMFkFkbWluQG9y\\nZzEuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2zFPDBYIy\\njZSXaB15ILW9MRUYkSiksD6Io+VBbsJex2S7Do7lJhYfpyg5Z1LEHLCQgHH/VJ1F\\nMZmNHgIIHqWPo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNV\\nHSMEJDAigCBrrGAVZjePzZuDxouWmQ1BrbUVMmQN6w6E+DzsHViX0jAKBggqhkjO\\nPQQDAgNIADBFAiEA0FGz0YuvjPaKGy0h7+AUGJ+02O78VIIJx3wX1SL0ODMCIHSN\\nDX1FwttwXOkNiLBOi9sz04bOXz6ALO0xXtZCE4pi\\n-----END CERTIFICATE-----\\n\\x12\\x18\\x94\\x13\\xc3\\xd9\\xb3\\xba\\xe7V\\xb8Z\\xd3\\xad\\x9b\\xb9<\\xbe\\xd1\\xc8Y\\xd9{\\xe1d\\xd5\\x12G0E\\x02!\\x00\\x9d\\x13\\xcb\\tz\\xe0\\xc2\\xc1\\xff\\xa0\\x84\\x14\\x97y\\x99m\\xab\\x9aD0L\\xc0]\\xdf|\\xfa\\xcc(\\x8d\\xc4\\x96\\x1c\\x02 <\\xff\\x91uy\\xd5\\x02\\xb1Y\\xa1\\xc8\\xc3'\\xf23c\\x890\\xd9\\xc3\\xdd>\\xb8\\xfb\\x81\\xe0\\x9d\\xf1\\x95T.\\xc1\"], 'config': b'\\n\\x0fbusinesschannel\\x12;\\x12)\\n\\x0bApplication\\x12\\x1a\\x12\\x0b\\n\\x07Org2MSP\\x12\\x00\\x12\\x0b\\n\\x07Org1MSP\\x12\\x00\\x1a\\x0e\\n\\nConsortium\\x12\\x00\\x1a\\xed\\x01\\x12\\xc6\\x01\\n\\x0bApplication\\x12\\xb6\\x01\\x08\\x01\\x12\\x0b\\n\\x07Org2MSP\\x12\\x00\\x12\\x0b\\n\\x07Org1MSP\\x12\\x00\\x1a$\\n\\x0cCapabilities\\x12\\x14\\x12\\n\\n\\x08\\n\\x04V1_3\\x12\\x00\\x1a\\x06Admins\"\"\\n\\x07Writers\\x12\\x17\\x12\\r\\x08\\x03\\x12\\t\\n\\x07Writers\\x1a\\x06Admins\"\"\\n\\x06Admins\\x12\\x18\\x12\\x0e\\x08\\x03\\x12\\n\\n\\x06Admins\\x10\\x02\\x1a\\x06Admins\"\"\\n\\x07Readers\\x12\\x17\\x12\\r\\x08\\x03\\x12\\t\\n\\x07Readers\\x1a\\x06Admins*\\x06Admins\\x1a\"\\n\\nConsortium\\x12\\x14\\x12\\x12\\n\\x10SampleConsortium', 'orderer': <hfc.fabric.orderer.Orderer object at 0x7f03b35556d8>, 'channel_name': 'businesschannel'}\n",
      "_create_or_update_channel - start\n",
      "_create_or_update_channel - have config_update\n",
      "New channel with name = businesschannel\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# Create a New Channel, the response should be true if succeed\n",
    "response = await cli.channel_create(\n",
    "                    orderer='orderer.example.com',\n",
    "                    channel_name='businesschannel',\n",
    "                    requestor=org1_admin,\n",
    "                    config_yaml='test/fixtures/e2e_cli/',\n",
    "                    channel_profile='TwoOrgsChannel'\n",
    "                    )\n",
    "\n",
    "# response = true is returned if the channel is created successfully\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the below code snippet to make the peers of Org1 join the channel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "get genesis block successfully, block=data_hash: \"\\217\\232\\252\\311\\240\\204\\332\\245\\203\\203\\313\\263$\\377A\\234\\037[:X\\300>\\246\\005\\266\\227\\322\\020\\244O4\\217\"\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# Join Peers into Channel, the response should be true if succeed\n",
    "responses = await cli.channel_join(\n",
    "                       requestor=org1_admin,\n",
    "                       channel_name='businesschannel',\n",
    "                       peers=['peer0.org1.example.com',\n",
    "                      'peer1.org1.example.com'],\n",
    "                       orderer='orderer.example.com'\n",
    "                       )\n",
    "\n",
    "# The length of the response should be two as len(peers) = 2\n",
    "print(len(responses) == 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the below code snippet to make the peers of Org1 join the channel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "get genesis block successfully, block=data_hash: \"\\217\\232\\252\\311\\240\\204\\332\\245\\203\\203\\313\\263$\\377A\\234\\037[:X\\300>\\246\\005\\266\\227\\322\\020\\244O4\\217\"\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# For operations on peers from org2.example.com, org2_admin is required as requestor\n",
    "responses = await cli.channel_join(\n",
    "                       requestor=org2_admin,\n",
    "                       channel_name='businesschannel',\n",
    "                       peers=['peer0.org2.example.com',\n",
    "                      'peer1.org2.example.com'],\n",
    "                       orderer='orderer.example.com'\n",
    "                       )\n",
    "\n",
    "# The length of the response should be two as len(peers) = 2\n",
    "print(len(responses) == 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the below code snippet to install an example chaincode which can be found at `test/fixtures/chaincode` on the peers of org1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This installs the example chaincode on the peers\n",
    "# Make the client know there is a channel in the network\n",
    "cli.new_channel('businesschannel')\n",
    "\n",
    "#The GOPTAH settings is required for only running the example chaincode in the SDK\n",
    "import os\n",
    "gopath_bak = os.environ.get('GOPATH', '')\n",
    "gopath = os.path.normpath(os.path.join(\n",
    "                      os.path.dirname(os.path.realpath('__file__')),\n",
    "                      'test/fixtures/chaincode'\n",
    "                     ))\n",
    "\n",
    "# The response should be true if succeed\n",
    "responses = loop.run_until_complete(cli.chaincode_install(\n",
    "               requestor=org1_admin,\n",
    "               peers=['peer0.org1.example.com',\n",
    "                      'peer1.org1.example.com'],\n",
    "               cc_path='github.com/example_cc',\n",
    "               cc_name='example_cc',\n",
    "               cc_version='v1.0'\n",
    "               ))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the below code snippet to instantiate the installed chaincode.\n",
    "During instantiation you should provide the endorsement policy for the chaincode.\n",
    "You can find more details regarding the endorsement policy [here](https://hyperledger-fabric.readthedocs.io/en/release-1.4/endorsement-policies.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Instantiate Chaincode in Channel, the response should be true if succeed\n",
    "args = ['a', '200', 'b', '300']\n",
    "\n",
    "# This policy specifies the endorsement policy which is required while instantiating the chaincode\n",
    "policy = {\n",
    "    'identities': [\n",
    "        {'role': {'name': 'member', 'mspId': 'Org1MSP'}},\n",
    "    ],\n",
    "    'policy': {\n",
    "        '1-of': [\n",
    "            {'signed-by': 0},\n",
    "        ]\n",
    "    }\n",
    "}\n",
    "response = loop.run_until_complete(cli.chaincode_instantiate(\n",
    "               requestor=org1_admin,\n",
    "               channel_name='businesschannel',\n",
    "               peers=['peer0.org1.example.com'],\n",
    "               args=args,\n",
    "               cc_name='example_cc',\n",
    "               cc_version='v1.0',\n",
    "               cc_endorsement_policy=policy, # optional, but recommended\n",
    "               collections_config=None, # optional, for private data policy\n",
    "               transient_map=None, # optional, for private data\n",
    "               wait_for_event=True # optional, for being sure chaincode is instantiated\n",
    "               ))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the below code snippet to invoke the installed chaincode with the arguments as mentioned in args."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Invoke a chaincode\n",
    "args = ['a', 'b', '100']\n",
    "# The response should be true if succeed\n",
    "response = loop.run_until_complete(cli.chaincode_invoke(\n",
    "               requestor=org1_admin,\n",
    "               channel_name='businesschannel',\n",
    "               peers=['peer0.org1.example.com'],\n",
    "               args=args,\n",
    "               cc_name='example_cc',\n",
    "               transient_map=None, # optional, for private data\n",
    "               wait_for_event=True, # for being sure chaincode invocation has been commited in the ledger, default is on tx event\n",
    "               #cc_pattern='^invoked*' # if you want to wait for chaincode event and you have a `stub.SetEvent(\"invoked\", value)` in your chaincode\n",
    "               ))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Query a chaincode\n",
    "args = ['b']\n",
    "# The response should be true if succeed\n",
    "response = loop.run_until_complete(cli.chaincode_query(\n",
    "               requestor=org1_admin,\n",
    "               channel_name='businesschannel',\n",
    "               peers=['peer0.org1.example.com'],\n",
    "               args=args,\n",
    "               cc_name='example_cc'\n",
    "               ))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
